/*
 * Swipe 1.0
 *
 * Brad Birdsall, Prime
 * Copyright 2011, Licensed GPL & MIT
 *
 */
$.Swipe = function(element, options) {
  // return immediately if element doesn't exist
  if (!element) return null;
  var _this = this;
  // retreive options
  this.options = options || {};
  this.index = this.options.startSlide || 0;
  this.speed = this.options.speed || 300;
  this.callback = this.options.callback || function() {};
  this.delay = this.options.auto || 0;
  this.direction = this.options.direction || "LMove";
  this.unresize = this.options.unresize; //anjey

  // reference dom elements
  this.container = element;
  this.element = this.container.children[0]; // the slide pane
  // static css
  //this.container.style.overflow = 'hidden'; //by anjey

  // trigger slider initialization
  this.setup();

  // begin auto slideshow
  this.begin();

  // add event listeners
  if (this.element.addEventListener) {
    //by anjey
    this.element.addEventListener('mousedown', this, false);
    this.element.addEventListener('touchstart', this, false);
    this.element.addEventListener('touchmove', this, false);
    this.element.addEventListener('touchend', this, false);
    this.element.addEventListener('webkitTransitionEnd', this, false);
    this.element.addEventListener('msTransitionEnd', this, false);
    this.element.addEventListener('oTransitionEnd', this, false);
    this.element.addEventListener('transitionend', this, false);
    if (!this.unresize) { // anjey
      window.addEventListener('resize', this, false);
    }
  }

};

$.Swipe.prototype = {
  setup: function() {

    // get and measure amt of slides
    this.slides = this.element.children;
    this.length = this.slides.length;
    this.height = this.container.getBoundingClientRect().height || this.height;
    this.width = this.container.getBoundingClientRect().width || this.width; //anjey
    // return immediately if their are less than two slides
    if (this.length < 1) return null;
    if (this.width || this.height) {
      var index = this.slides.length;
      if (this.direction == "LMove") {
        this.element.style.width = (this.slides.length * this.width) + 'px';
        // this.height = this.slides[0].clientHeight;
      } else if (this.direction == "TMove") {
        this.element.style.height = (this.slides.length * this.height) + 'px';
      }
      while (index--) {
        var el = this.slides[index];
        el.style.width = this.width + 'px';
        el.style.height = this.height + 'px';
        el.style.lineHeight = this.height + 'px';
        if (this.direction == "LMove") {
          el.style.cssFloat = "left";
        }
        //el.style.display = 'table-cell';
        //el.style.verticalAlign = 'top';
      }
      // set start position and force translate to remove initial flickering
      this.slide(this.index, 0);
      // show slider element
      //this.container.style.visibility = 'visible'; 
    }

  },

  slide: function(index, duration) {

    var style = this.element.style;

    // fallback to default speed
    if (duration == undefined) {
      duration = this.speed;
    }

    // set duration speed (0 represents 1-to-1 scrolling)
    style.webkitTransitionDuration = style.MozTransitionDuration = style.msTransitionDuration = style.OTransitionDuration = style.transitionDuration = duration + 'ms';
    if (this.direction == "LMove") {
      // translate to given index position
      style.MozTransform = style.webkitTransform = 'translateX(' + -(index * this.width) + 'px)';
      style.msTransform = style.OTransform = 'translateX(' + -(index * this.width) + 'px)';
    } else if (this.direction == "TMove") {
      style.MozTransform = style.webkitTransform = 'translateY(' + -(index * this.height) + 'px)';
      style.msTransform = style.OTransform = 'translateY(' + -(index * this.height) + 'px)';
    }

    // set new index to allow for expression arguments
    this.index = index;

  },

  getPos: function() {

    // return current index position
    return this.index;

  },

  prev: function(delay) {

    // cancel next scheduled automatic transition, if any
    this.delay = delay || 0;
    clearTimeout(this.interval);

    // if not at first slide
    if (this.index) this.slide(this.index - 1, this.speed);

  },

  next: function(delay) {

    // cancel next scheduled automatic transition, if any
    this.delay = delay || 0;
    clearTimeout(this.interval);

    if (this.index < this.length - 1) this.slide(this.index + 1, this.speed); // if not last slide
    else this.slide(0, this.speed); //if last slide return to start

  },

  begin: function() {

    var _this = this;

    this.interval = (this.delay) ? setTimeout(function() {
      _this.next(_this.delay);
    }, this.delay) : 0;

  },

  stop: function() {
    this.delay = 0;
    clearTimeout(this.interval);
  },

  resume: function() {
    this.delay = this.options.auto || 0;
    this.begin();
  },

  handleEvent: function(e) {
    var that = this;
    if (!e.touches) {
      e.touches = new Array(e);
      e.scale = false;
    }
    switch (e.type) {
      // by anjey
      case 'mousedown':
        (function() {
          that.element.addEventListener('mousemove', that, false);
          that.element.addEventListener('mouseup', that, false);
          that.element.addEventListener('mouseout', that, false);
          that.onTouchStart(e);
        })();
        break;
      case 'mousemove':
        this.onTouchMove(e);
        break;
      case 'mouseup':
        (function() {
          that.element.removeEventListener('mousemove', that, false);
          that.element.removeEventListener('mouseup', that, false);
          that.element.removeEventListener('mouseout', that, false);
          that.onTouchEnd(e);
        })();
        break;
      case 'mouseout':
        (function() {
          that.element.removeEventListener('mousemove', that, false);
          that.element.removeEventListener('mouseup', that, false);
          that.element.removeEventListener('mouseout', that, false);
          that.onTouchEnd(e);
        })();
        break;

      case 'touchstart':
        this.onTouchStart(e);
        break;
      case 'touchmove':
        this.onTouchMove(e);
        break;
      case 'touchend':
        this.onTouchEnd(e);
        break;
      case 'webkitTransitionEnd':
      case 'msTransitionEnd':
      case 'oTransitionEnd':
      case 'transitionend':
        this.transitionEnd(e);
        break;
      case 'resize':
        this.setup();
        break;
    }
  },

  transitionEnd: function(e) {
    e.preventDefault();
    if (this.delay) this.begin();

    this.callback(e, this.index, this.slides[this.index]);

  },

  onTouchStart: function(e) {

    this.start = {

      // get touch coordinates for delta calculations in onTouchMove
      pageX: e.touches[0].pageX,
      pageY: e.touches[0].pageY,

      // set initial timestamp of touch sequence
      time: Number(new Date())

    };

    // used for testing first onTouchMove event
    this.isScrolling = undefined;

    // reset deltaX
    this.deltaX = 0;
    this.deltaY = 0;
    // set transition time to 0 for 1-to-1 touch movement
    this.element.style.MozTransitionDuration = this.element.style.webkitTransitionDuration = 0;

  },
  onTouchMove: function(e) {
    // ensure swiping with one touch and not pinching
    if (e.touches.length > 1 || e.scale && e.scale !== 1) return;


    this.deltaX = e.touches[0].pageX - this.start.pageX;
    this.deltaY = e.touches[0].pageY - this.start.pageY;
    if (this.direction == "LMove") {
      // determine if scrolling test has run - one time test
      if (typeof this.isScrolling == 'undefined') {
        this.isScrolling = !!(this.isScrolling || Math.abs(this.deltaX) < Math.abs(e.touches[0].pageY - this.start.pageY));
      }
      // if user is not trying to scroll vertically
      if (!this.isScrolling) {
        // prevent native scrolling 
        e.preventDefault();
        // cancel slideshow
        clearTimeout(this.interval);
        // increase resistance if first or last slide
        this.deltaX =
          this.deltaX /
          ((!this.index && this.deltaX > 0 // if first slide and sliding left
              || this.index == this.length - 1 // or if last slide and sliding right
              && this.deltaX < 0 // and if sliding at all
            ) ?
            (Math.abs(this.deltaX) / this.width + 1) // determine resistance level
            : 1); // no resistance if false

        // translate immediately 1-to-1
        this.element.style.MozTransform = this.element.style.webkitTransform = 'translateX(' + (this.deltaX - this.index * this.width) + 'px)';
      }
    } else if (this.direction == "TMove") {
      if (typeof this.isScrolling == 'undefined') {
        this.isScrolling = !!(this.isScrolling || Math.abs(this.deltaY) < Math.abs(e.touches[0].pageX - this.start.pageX));
      }
      if (!this.isScrolling) {
        e.preventDefault();
        clearTimeout(this.interval);
        this.deltaY = this.deltaY / ((!this.index && this.deltaY > 0 || this.index == this.length - 1 && this.deltaY < 0) ? (Math.abs(this.deltaY) / this.height + 1) : 1);
        this.element.style.MozTransform = this.element.style.webkitTransform = 'translateY(' + (this.deltaY - this.index * this.height) + 'px)';
      }
    }
  },
  onTouchEnd: function(e) {

    if (this.direction == "LMove") {
      // determine if slide attempt triggers next/prev slide
      var isValidSlide =
        Number(new Date()) - this.start.time < 250 // if slide duration is less than 250ms
        && Math.abs(this.deltaX) > 20 // and if slide amt is greater than 20px
        || Math.abs(this.deltaX) > this.width / 2, // or if slide amt is greater than half the width
        // determine if slide attempt is past start and end
        isPastBounds = !this.index && this.deltaX > 0 // if first slide and slide amt is greater than 0
        || this.index == this.length - 1 && this.deltaX < 0; // or if last slide and slide amt is less than 0
      // if not scrolling vertically
      if (!this.isScrolling) {
        // call slide function with slide end value based on isValidSlide and isPastBounds tests
        this.slide(this.index + (isValidSlide && !isPastBounds ? (this.deltaX < 0 ? 1 : -1) : 0), this.speed);
      }
    } else if (this.direction == "TMove") {
      var isValidSlide = Number(new Date()) - this.start.time < 250 && Math.abs(this.deltaY) > 20 || Math.abs(this.deltaY) > 15,
        isPastBounds = !this.index && this.deltaY > 0 || this.index == this.length - 1 && this.deltaY < 0;
      if (!this.isScrolling) {
        this.slide(this.index + (isValidSlide && !isPastBounds ? (this.deltaY < 0 ? 1 : -1) : 0), this.speed);
      }
    }
  }
};